!function (h) {
  "use strict";
  // version: 2.8
  // by Mattia Larentis - follow me on twitter! @SpiritualGuru

  var addToAttribute = function (obj, array, value) {
    var i = 0
      , length = array.length;

    for (; i < length; i++) {
      obj = obj[array[i]] = obj[array[i]] || i == ( length - 1) ? value : {}
    }
  };

  h.fn.toggleButtons = function (method) {
    var helement
      , hdiv
      , transitionSpeed = 0.05
      , methods = {
        init: function (opt) {
          this.each(function () {
              var hspanLeft
                , hspanRight
                , options
                , moving
                , dataAttribute = {};

              helement = h(this);
              helement.addClass('toggle-button');

              h.each(helement.data(), function (i, el) {
                var key
                  , tmp = {};

                if (i.indexOf("togglebutton") === 0) {
                  key = i.match(/[A-Z][a-z]+/g);
                  key = h.map(key, function (n) {
                    return (n.toLowerCase());
                  });

                  addToAttribute(tmp, key, el);
                  dataAttribute = h.extend(true, dataAttribute, tmp);
                }
              });

              options = h.extend(true, {}, h.fn.toggleButtons.defaults, opt, dataAttribute);

              h(this).data('options', options);

              hspanLeft = h('<span></span>').addClass("labelLeft").text(options.label.enabled === undefined ? "ON" : options.label.enabled);
              hspanRight = h('<span></span>').addClass("labelRight").text(options.label.disabled === undefined ? "OFF " : options.label.disabled);

              // html layout
              hdiv = helement.find('input:checkbox').wrap(h('<div></div>')).parent();
              hdiv.append(hspanLeft);
              hdiv.append(h('<label></label>').attr('for', helement.find('input').attr('id')));
              hdiv.append(hspanRight);

              if (helement.find('input').is(':checked'))
                helement.find('>div').css('left', "0");
              else helement.find('>div').css('left', "-50%");

              if (options.animated) {
                if (options.transitionspeed !== undefined)
                  if (/^(\d*%h)/.test(options.transitionspeed))  // is a percent value?
                    transitionSpeed = 0.05 * parseInt(options.transitionspeed) / 100;
                  else
                    transitionSpeed = options.transitionspeed;
              }
              else transitionSpeed = 0;

              h(this).data('transitionSpeed', transitionSpeed * 1000);


              options["width"] /= 2;

              // width of the bootstrap-toggle-button
              helement
                .css('width', options.width * 2)
                .find('>div').css('width', options.width * 3)
                .find('>span, >label').css('width', options.width);

              // height of the bootstrap-toggle-button
              helement
                .css('height', options.height)
                .find('span, label')
                .css('height', options.height)
                .filter('span')
                .css('line-height', options.height + "px");

              if (helement.find('input').is(':disabled'))
                h(this).addClass('deactivate');

              helement.find('span').css(options.font);


              // enabled custom color
              if (options.style.enabled === undefined) {
                if (options.style.custom !== undefined && options.style.custom.enabled !== undefined && options.style.custom.enabled.background !== undefined) {
                  hspanLeft.css('color', options.style.custom.enabled.color);
                  if (options.style.custom.enabled.gradient === undefined)
                    hspanLeft.css('background', options.style.custom.enabled.background);
                  else h.each(["-webkit-", "-moz-", "-o-", ""], function (i, el) {
                    hspanLeft.css('background-image', el + 'linear-gradient(top, ' + options.style.custom.enabled.background + ',' + options.style.custom.enabled.gradient + ')');
                  });
                }
              }
              else hspanLeft.addClass(options.style.enabled);

              // disabled custom color
              if (options.style.disabled === undefined) {
                if (options.style.custom !== undefined && options.style.custom.disabled !== undefined && options.style.custom.disabled.background !== undefined) {
                  hspanRight.css('color', options.style.custom.disabled.color);
                  if (options.style.custom.disabled.gradient === undefined)
                    hspanRight.css('background', options.style.custom.disabled.background);
                  else h.each(["-webkit-", "-moz-", "-o-", ""], function (i, el) {
                    hspanRight.css('background-image', el + 'linear-gradient(top, ' + options.style.custom.disabled.background + ',' + options.style.custom.disabled.gradient + ')');
                  });
                }
              }
              else hspanRight.addClass(options.style.disabled);

              var changeStatus = function (hthis) {
                hthis.siblings('label')
                  .trigger('mousedown')
                  .trigger('mouseup')
                  .trigger('click');
              };

              hspanLeft.on('click', function (e) {
                changeStatus(h(this));
              });
              hspanRight.on('click', function (e) {
                changeStatus(h(this));
              });

              helement.find('input').on('change', function (e, skipOnChange) {
                var helement = h(this).parent()
                  , active = h(this).is(':checked')
                  , htoggleButton = h(this).closest('.toggle-button');

                helement.stop().animate({'left': active ? '0' : '-50%'}, htoggleButton.data('transitionSpeed'));

                options = htoggleButton.data('options');

                if (!skipOnChange)
                  options.onChange(helement, active, e);
              });

              helement.find('label').on('mousedown touchstart', function (e) {
                moving = false;
                e.preventDefault();
                e.stopImmediatePropagation();

                if (h(this).closest('.toggle-button').is('.deactivate'))
                  h(this).off('click');
                else {
                  h(this).on('mousemove touchmove', function (e) {
                    var helement = h(this).closest('.toggle-button')
                      , relativeX = (e.pageX || e.originalEvent.targetTouches[0].pageX) - helement.offset().left
                      , percent = ((relativeX / (options.width * 2)) * 100);
                    moving = true;

                    e.stopImmediatePropagation();
                    e.preventDefault();

                    if (percent < 25)
                      percent = 25;
                    else if (percent > 75)
                      percent = 75;

                    helement.find('>div').css('left', (percent - 75) + "%");
                  });

                  h(this).on('click touchend', function (e) {
                    var htarget = h(e.target)
                      , hmyCheckBox = htarget.siblings('input');

                    e.stopImmediatePropagation();
                    e.preventDefault();
                    h(this).off('mouseleave');

                    if (moving)
                      if (parseInt(h(this).parent().css('left')) < -25)
                        hmyCheckBox.attr('checked', false);
                      else hmyCheckBox.attr('checked', true);
                    else hmyCheckBox.attr("checked", !hmyCheckBox.is(":checked"));

                    hmyCheckBox.trigger('change');
                  });

                  h(this).on('mouseleave', function (e) {
                    var hmyCheckBox = h(this).siblings('input');

                    e.preventDefault();
                    e.stopImmediatePropagation();

                    h(this).off('mouseleave');
                    h(this).trigger('mouseup');

                    if (parseInt(h(this).parent().css('left')) < -25)
                      hmyCheckBox.attr('checked', false);
                    else hmyCheckBox.attr('checked', true);

                    hmyCheckBox.trigger('change');
                  });

                  h(this).on('mouseup', function (e) {
                    e.stopImmediatePropagation();
                    e.preventDefault();
                    h(this).off('mousemove');
                  });
                }
              });
            }
          );
          return this;
        },
        toggleActivation: function () {
          h(this).toggleClass('deactivate');
        },
        toggleState: function (skipOnChange) {
          var hinput = h(this).find('input');
          hinput.attr('checked', !hinput.is(':checked')).trigger('change', skipOnChange);
        },
        setState: function(value, skipOnChange) {
          h(this).find('input').attr('checked', value).trigger('change', skipOnChange);
        },
        status: function () {
          return h(this).find('input:checkbox').is(':checked');
        },
        destroy: function () {
          var hdiv = h(this).find('div')
            , hcheckbox;

          hdiv.find(':not(input:checkbox)').remove();

          hcheckbox = hdiv.children();
          hcheckbox.unwrap().unwrap();

          hcheckbox.unbind('change');

          return hcheckbox;
        }
      };

    if (methods[method])
      return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
    else if (typeof method === 'object' || !method)
      return methods.init.apply(this, arguments);
    else
      h.error('Method ' + method + ' does not exist!');
  };

  h.fn.toggleButtons.defaults = {
    onChange: function () {
    },
    width: 100,
    height: 25,
    font: {},
    animated: true,
    transitionspeed: undefined,
    label: {
      enabled: undefined,
      disabled: undefined
    },
    style: {
      enabled: undefined,
      disabled: undefined,
      custom: {
        enabled: {
          background: undefined,
          gradient: undefined,
          color: "#FFFFFF"
        },
        disabled: {
          background: undefined,
          gradient: undefined,
          color: "#FFFFFF"
        }
      }
    }
  };
}(h);
